﻿using ImageK.Gui;
using ImageK.Java;
using ImageK.Measure;
using ImageK.Process;
using ImageK.Util;
using System;
using System.Collections.Generic;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ImageK.Plugin
{

    /** This plugin implements the Edit/Selection/Scale command. */
    public class RoiScaler : PlugIn
    {

        private static double defaultXScale = 1.5;
        private static double defaultYScale = 1.5;
        private double xscale;
        private double yscale;
        private bool centered;

        public void run(String arg)
        {
            ImagePlus imp = IJ.getImage();
            Roi roi = imp.getRoi();
            if (roi==null)
            {
                IJ.error("Scale", "This command requires a selection");
                return;
            }
            if (!IJ.isMacro() && !imp.okToDeleteRoi())
                return;
            if (!showDialog())
                return;
            if (!IJ.MacroRunning())
            {
                defaultXScale = xscale;
                defaultYScale = yscale;
            }
            Roi roi2 = scale(roi, xscale, yscale, centered);
            if (roi2==null)
                return;
            Undo.setup(Undo.ROI, imp);
            roi = (Roi)roi.clone();
            imp.setRoi(roi2);
            Roi.setPreviousRoi(roi);
        }

        public bool showDialog()
        {
            GenericDialog gd = new GenericDialog("Scale Selection");
            gd.addNumericField("X scale factor:", defaultXScale, 2, 4, "");
            gd.addNumericField("Y scale factor:", defaultYScale, 2, 4, "");
            gd.addCheckbox("Centered", false);
            gd.showDialog();
            if (gd.wasCanceled())
                return false;
            xscale = gd.getNextNumber();
            yscale = gd.getNextNumber();
            centered = gd.getNextBoolean();
            return true;
        }

        public static Roi scale(Roi roi, double xscale, double yscale, bool centered)
        {
            if (roi is ShapeRoi)
			    return scaleShape((ShapeRoi)roi, xscale, yscale, centered);

            else if (roi is TextRoi)
			    return scaleText((TextRoi)roi, xscale, yscale, centered);

            else if (roi is ImageRoi)
			    return scaleImage((ImageRoi)roi, xscale, yscale, centered);
            FloatPolygon poly = roi.getFloatPolygon();
            int type = roi.getType();
            if (type==Roi.LINE)
            {
                Line line = (Line)roi;
                double x1 = line.x1d;
                double y1 = line.y1d;
                double x2 = line.x2d;
                double y2 = line.y2d;
                poly = new FloatPolygon();
                poly.addPoint(x1, y1);
                poly.addPoint(x2, y2);
            }
            ImageStatistics stats = null;
            if (centered)
            {
                ImagePlus imp = roi.getImage();
                if (imp==null)
                {
                    Rectangle r = roi.getBounds();
                    imp = IJ.createImage("Untitled", "8-bit black", r.X+r.Width, r.Y+r.Height, 1);
                }
                ImageProcessor ip = imp.getProcessor();
                ip.setRoi(roi);
                stats = ImageStatistics.getStatistics(ip, Measurements.CENTROID, null);
                if (roi.isLine())
                {
                    Rectangle r = roi.getBounds();
                    stats.xCentroid = r.X + Math.Round(r.Width/2.0);
                    stats.yCentroid = r.Y + Math.Round(r.Height/2.0);
                }
            }
            for (int i = 0; i<poly.npoints; i++)
            {
                if (centered)
                {
                    poly.xpoints[i] = (float)Math.Round((poly.xpoints[i]-stats.xCentroid)*xscale+stats.xCentroid);
                    poly.ypoints[i] = (float)Math.Round((poly.ypoints[i]-stats.yCentroid)*yscale+stats.yCentroid);
                }
                else
                {
                    poly.xpoints[i] = (float)(poly.xpoints[i]*xscale);
                    poly.ypoints[i] = (float)(poly.ypoints[i]*yscale);
                }
            }
            Roi roi2 = null;
            if (type==Roi.LINE)
                roi2 = new Line(poly.xpoints[0], poly.ypoints[0], poly.xpoints[1], poly.ypoints[1]);
            else if (type==Roi.POINT)
                roi2 = new PointRoi(poly.xpoints, poly.ypoints, poly.npoints);
            else
            {
                if (type==Roi.RECTANGLE)
                    type = Roi.POLYGON;
                if (type==Roi.RECTANGLE && poly.npoints>4) // rounded rectangle
                    type = Roi.FREEROI;
                if (type==Roi.OVAL||type==Roi.TRACED_ROI)
                    type = Roi.FREEROI;
                roi2 = new PolygonRoi(poly.xpoints, poly.ypoints, poly.npoints, type);
            }
            roi2.copyAttributes(roi);
            double width = roi.getStrokeWidth();
            if (width!=0)
                roi2.setStrokeWidth(width*xscale);
            return roi2;
        }

        private static Roi scaleShape(ShapeRoi roi, double xscale, double yscale, bool centered)
        {
            throw new NotImplementedException();
            // Rectangle r = roi.getBounds();
            // Shape shape = roi.getShape();
            // AffineTransform at = new AffineTransform();
            // at.scale(xscale, yscale);
            // if (!centered)
            //     at.translate(r.x, r.y);
            // Shape shape2 = at.createTransformedShape(shape);
            // Roi roi2 = new ShapeRoi(shape2);
            // if (centered)
            // {
            //     int xbase = (int)(centered ? r.x-(r.width*xscale-r.width)/2.0 : r.x);
            //     int ybase = (int)(centered ? r.y-(r.height*yscale-r.height)/2.0 : r.y);
            //     roi2.setLocation(xbase, ybase);
            // }
            // roi2.copyAttributes(roi);
            // double width = roi.getStrokeWidth();
            // if (width!=0)
            //     roi2.setStrokeWidth(width*xscale);
            // return roi2;
        }

        private static Roi scaleText(TextRoi roi, double xscale, double yscale, bool centered)
        {
            Rectangle bounds = roi.getBounds();
            int x = (int)Math.Round(bounds.X*xscale);
            int y = (int)Math.Round(bounds.Y*yscale);
            Font font = roi.getCurrentFont();
            font = font.deriveFont((float)(font.Size*yscale));
            Roi roi2 = new TextRoi(x, y, roi.getText(), font);
            roi2.copyAttributes(roi);
            return roi2;
        }

        private static Roi scaleImage(ImageRoi roi, double xscale, double yscale, bool centered)
        {
            roi = (ImageRoi)roi.clone();
            ImageProcessor ip2 = roi.getProcessor();
            //ip2.setInterpolationMethod(interpolationMethod);
            int newWidth = (int)Math.Round(ip2.getWidth()*xscale);
            int newHeight = (int)Math.Round(ip2.getHeight()*yscale);
            ip2 = ip2.resize(newWidth, newHeight, true);
            roi.setProcessor(ip2);
            Rectangle bounds = roi.getBounds();
            int x = (int)Math.Round(bounds.X*xscale);
            int y = (int)Math.Round(bounds.Y*yscale);
            roi.setLocation(x, y);
            roi.copyAttributes(roi);
            return roi;
        }

    }

}
